#include <iostream>

using namespace std;

namespace wjh
{
	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}

		unique_ptr(const unique_ptr<T>& up) = delete;

		unique_ptr<T>&	 operator=(const unique_ptr<T>& up) = delete;

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		~unique_ptr()
		{
			if (_ptr)
			{
				cout << "delete" << _ptr << endl;
				delete _ptr;
			}
		}

	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pCount(new int(1))
		{}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pCount(sp._pCount)
		{
			++(*_pCount);
		}

		shared_ptr<T>&	 operator=(const shared_ptr<T>& sp)
		{
			if (_ptr == sp._ptr)
			{
				return *this;
			}

			if (--(*_pCount) == 0)
			{
				delete _ptr;
				delete _pCount;
			}

			_ptr = sp._ptr;
			_pCount = sp._pCount;
			(*_pCount)++;

			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		T* get() const
		{
			return _ptr;
		}

		bool operator !=(const shared_ptr<T>& sp)
		{
			return this != (&sp);
		}

		~shared_ptr()
		{
			if (--(*_pCount) == 0)
			{
				cout << "delete" << _ptr << endl;
				delete _ptr;
				delete _pCount;
			}
		}

	private:
		T* _ptr;
		int* _pCount;
	};

	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}

		weak_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
		{}

		weak_ptr<T>& operator=(const weak_ptr<T>& wp)
		{
			if (_ptr == wp._ptr)
			{
				return *this;
			}

			_ptr = wp._ptr;

			return *this;
		}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
	};
}